package org.nehc.algorithm.redissonutils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;

import java.time.Duration;
import java.util.*;

/**
 * Redisson 集合缓存操作工具类
 * 提供List、Set、Map等集合类型的缓存操作
 *
 * @author system
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class RedissonCollectionUtils {

    private static final RedissonClient CLIENT = RedissonUtils.getClient();

    // ==================== List 操作 ====================

    /**
     * 缓存List数据
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param dataList  待缓存的List数据
     * @return 缓存的对象
     */
    public static <T> boolean setCacheList(final String cacheName, final String key, final List<T> dataList) {
        return setCacheList(cacheName, key, dataList, null);
    }

    /**
     * 缓存List数据
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param dataList  待缓存的List数据
     * @param duration  过期时间
     * @return 缓存的对象
     */
    public static <T> boolean setCacheList(final String cacheName, final String key, final List<T> dataList, final Duration duration) {
        try {
            RList<T> rList = CLIENT.getList(RedissonUtils.getKey(cacheName, key));
            rList.clear();
            boolean result = rList.addAll(dataList);
            if (duration != null) {
                rList.expire(duration);
            }
            return result;
        } catch (Exception e) {
            log.error("设置缓存List失败，key: {}", key, e);
            return false;
        }
    }

    /**
     * 替换缓存List数据
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param dataList  待缓存的List数据
     * @param duration  过期时间
     * @return 缓存的对象
     */
    public static <T> boolean replaceCacheList(final String cacheName, final String key, final List<T> dataList, final Duration duration) {
        try {
            RList<T> rList = CLIENT.getList(RedissonUtils.getKey(cacheName, key));
            rList.delete();
            boolean result = rList.addAll(dataList);
            if (duration != null) {
                rList.expire(duration);
            }
            return result;
        } catch (Exception e) {
            log.error("替换缓存List失败，key: {}", key, e);
            return false;
        }
    }

    /**
     * 替换缓存List数据
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param dataList  待缓存的List数据
     * @return 缓存的对象
     */
    public static <T> boolean replaceCacheList(final String cacheName, final String key, final List<T> dataList) {
        return replaceCacheList(cacheName, key, dataList, null);
    }

    /**
     * 向List右侧添加数据
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param data      待缓存的data数据
     * @param finalSize 指定最终的长度
     * @return 缓存的对象
     */
    public static <T> boolean listRightPush(final String cacheName, final String key, final T data, final int finalSize) {
        RList<T> rList = CLIENT.getList(RedissonUtils.getKey(cacheName, key));
        int currentSize = rList.size();
        if (currentSize >= finalSize) {
            rList.trim(currentSize - finalSize, currentSize - 1);
        }
        return rList.add(data);
    }

    /**
     * 注册List监听器
     * <p>
     * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param listener  监听器配置
     */
    public static <T> void addListListener(final String cacheName, final String key, final ObjectListener listener) {
        RList<T> rList = CLIENT.getList(RedissonUtils.getKey(cacheName, key));
        rList.addListener(listener);
    }

    /**
     * 获得缓存的list对象，优先从本地缓存获取，本地缓存未命中则从Redis获取
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @return 缓存键值对应的数据
     */
    public static <T> List<T> getCacheList(final String cacheName, final String key) {
        return RedissonUtils.getFromLocalCacheOrRedis(cacheName, key, redisKey -> {
            String fullKey = RedissonUtils.getKey(cacheName, redisKey);
            RList<T> rList = CLIENT.getList(fullKey);
            List<T> result = rList.readAll();
            return result.isEmpty() ? null : result;
        });
    }

    // ==================== Set 操作 ====================

    /**
     * 缓存Set
     *
     * @param cacheName 缓存名称
     * @param key       缓存键值
     * @param dataSet   缓存的数据
     * @return 缓存数据的对象
     */
    public static <T> boolean setCacheSet(final String cacheName, final String key, final Set<T> dataSet) {
        RSet<T> rSet = CLIENT.getSet(RedissonUtils.getKey(cacheName, key));
        return rSet.addAll(dataSet);
    }

    /**
     * 注册Set监听器
     * <p>
     * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param listener  监听器配置
     */
    public static <T> void addSetListener(final String cacheName, final String key, final ObjectListener listener) {
        RSet<T> rSet = CLIENT.getSet(RedissonUtils.getKey(cacheName, key));
        rSet.addListener(listener);
    }

    /**
     * 获得缓存的set
     *
     * @param cacheName 缓存名称
     * @param key       缓存的key
     * @return set对象
     */
    public static <T> Set<T> getCacheSet(final String cacheName, final String key) {
        RSet<T> rSet = CLIENT.getSet(RedissonUtils.getKey(cacheName, key));
        return rSet.readAll();
    }

    /**
     * 异步获得缓存的set
     *
     * @param cacheName 缓存名称
     * @param key       缓存的key
     * @return set对象
     */
    @SneakyThrows
    public static <T> Set<T> getCacheSetAsync(final String cacheName, final String key) {
        RSet<T> rSet = CLIENT.getSet(RedissonUtils.getKey(cacheName, key));
        RFuture<Set<T>> set = rSet.readAllAsync();
        return set.get();
    }

    // ==================== Map 操作 ====================

    /**
     * 缓存Map
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param dataMap   缓存的数据
     * @param duration  过期时间
     */
    public static <K, T> void setCacheMap(final String cacheName, final String key, final Map<K, T> dataMap, Duration duration) {
        if (dataMap != null) {
            RMap<K, T> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
            rMap.putAll(dataMap);
            Optional.ofNullable(duration).ifPresent(rMap::expire);
        }
    }

    /**
     * 缓存Map
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param dataMap   缓存的数据
     */
    public static <K, T> void setCacheMap(final String cacheName, final String key, final Map<K, T> dataMap) {
        setCacheMap(cacheName, key, dataMap, null);
    }

    /**
     * 注册Map监听器
     * <p>
     * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @param listener  监听器配置
     */
    public static <T> void addMapListener(final String cacheName, final String key, final ObjectListener listener) {
        RMap<String, T> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
        rMap.addListener(listener);
    }

    /**
     * 获得缓存的Map
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @return map对象
     */
    public static <K, T> Map<K, T> getCacheMap(final String cacheName, final String key) {
        RMap<K, T> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
        return rMap.getAll(rMap.keySet());
    }

    /**
     * 获得缓存Map的key列表
     *
     * @param cacheName 缓存名称
     * @param key       缓存的键值
     * @return key列表
     */
    public static <T> Set<String> getCacheMapKeySet(final String cacheName, final String key) {
        RMap<String, T> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
        return rMap.keySet();
    }

    /**
     * 往Hash中存入数据
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param hKey      Hash键
     * @param value     值
     */
    public static <T> void setCacheMapValue(final String cacheName, final String key, final String hKey, final T value) {
        RMap<String, T> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
        rMap.put(hKey, value);
    }

    /**
     * 获取Hash中的数据
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param hKey      Hash键
     * @return Hash中的对象
     */
    public static <T> T getCacheMapValue(final String cacheName, final String key, final String hKey) {
        RMap<String, T> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
        return rMap.get(hKey);
    }

    /**
     * 删除Hash中的数据
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param hKey      Hash键
     * @return Hash中的对象
     */
    public static <T> T delCacheMapValue(final String cacheName, final String key, final String hKey) {
        RMap<String, T> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
        return rMap.remove(hKey);
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param hKeys     Hash键集合
     * @return Hash对象集合
     */
    public static <K, V> Map<K, V> getMultiCacheMapValue(final String cacheName, final String key, final Set<K> hKeys) {
        RMap<K, V> rMap = CLIENT.getMap(RedissonUtils.getKey(cacheName, key));
        return rMap.getAll(hKeys);
    }
}